#include "common.h"
#include "my_hash.h"
#include "bitio.h"

int lzcompress(char* source_file,char* dest_file){	

	char c;
	node* tab;
	struct stat st;
	int ret = 0	, i = 0, len = 0;
	int file_size;
	int bit_da_scrivere = 9;
	BITFILE *bitbuff;

	value_t current_dad = ROOT_INDEX;
	value_t current_value = ROOT_INDEX;	
	value_t next_value = ROOT_INDEX +1;	
	
	/*** apertura file da comprimere***/
	FILE *fd = fopen(source_file,"r");
	if(fd == NULL){
		fprintf(stderr,"Impossibile aprire il file %s. Chiusura in corso...\n", source_file);
		return -1;	
	}
	stat(source_file, &st);
	file_size = st.st_size;
	
	/*** allocazione hash per la compressione e inizializzazione ***/
	tab = calloc(M1_ENTRY, sizeof(node));	
	if (tab==NULL){
		fprintf(stderr, "Errore nell'allocazione della memoria!\n");
		fclose(fd);	
		return -1;
	}
	h_init(tab);
	
	/*** apertura file in cui verranno scritti i dati compressi e inizializzazione struttura bitbuff***/
	bitbuff = bit_open(dest_file, 1);
	if (bitbuff == NULL){
		fprintf(stderr,"Impossibile allocare un nuovo elemento bitbuff. Chiusura in corso...\n");
		fclose(fd);
		free(tab);
		return -1;
	}
	/*** inizio compressione ***/
	for(;i<file_size;i=i+len){
		
		/*** leggo un carattere ***/
 		len = fread(&c,1,1,fd);	
			
		/*** cerco un match nel nodo corrente ***/
		current_value = h_get(tab,current_dad,c);
		
#ifdef VERBOSE		
			printf("%c",c);	
#endif	
		/*** figlio non presente ***/
		if(current_value == -1){			

#ifdef VERBOSE		
			printf("\t<%d>\t:%d\tbit:%d\n",current_dad,bit_da_scrivere);
#endif
		
			bit_da_scrivere = ceil((log(next_value)/LOG2));
			ret= bit_write_opt (bitbuff, current_dad,bit_da_scrivere);
				
			if (ret < bit_da_scrivere) {
				fprintf(stderr, "Si è verificato un errore nella scrittura del file.\n");
				free(tab);
				fclose(fd);
				bit_close(bitbuff);
				return -1;
			}
			/*** inserisco un nuovo nodo e torno alla radice ***/
			h_insert(tab,current_dad,c,next_value);
			next_value++;
			current_dad = ROOT_INDEX;
			
			if (next_value == M_ENTRY){
		
				h_flush(tab);
				//printf("======================\n");
				next_value = ROOT_INDEX +1;
			}			

			current_value = h_get(tab,current_dad,c); // match sempre vero poichè current_dad è ROOT_INDEX

#ifdef VERBOSE		
			printf("%c",c);	
#endif
		}

		/*** aggiorno il nodo corrente per spostarmi lungo l'albero ***/
		current_dad = current_value;			
	}
	
	/*** scrivo l'ultimo valore ***/
	bit_da_scrivere = ceil((log(next_value)/log(2)));
	ret= bit_write_opt (bitbuff, current_dad, bit_da_scrivere);
	if (ret < bit_da_scrivere) {
		fprintf(stderr, "Si è verificato un errore nella scrittura del file.\n");
		free(tab);
		fclose(fd);
		bit_close(bitbuff);
		return -1;
	}
		/*** scrivo ROOT INDEX per notificare la fine del file ***/
	ret=bit_write_opt(bitbuff,ROOT_INDEX,bit_da_scrivere);
	if (ret < bit_da_scrivere) {
		fprintf(stderr, "Si è verificato un errore nella scrittura del file.\n");
		free(tab);
		fclose(fd);
		bit_close(bitbuff);
		return -1;
	}
	printf("\nScrittura Terminata.\n");
	
	free(tab);
	bit_close(bitbuff);
	fclose(fd);
	
return 0;
}
